/*
 * /linux-3.0.8/drivers/spi/gt2440_nrf2401.c
 */
 
#include <linux/init.h>
#include <linux/module.h>
#include <linux/ioctl.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/list.h>
#include <linux/errno.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/compat.h>
#include <linux/time.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/io.h>
#include <linux/spi/spi.h>

#include <mach/irqs.h>
#include <mach/gpio-nrs.h>

#include <mach/regs-gpio.h>

#include <asm/uaccess.h>


#include "gt2440_nrf2401.h"
#include "nrf2401_test.h"


static DECLARE_BITMAP(minors, N_SPI_MINORS);
static LIST_HEAD(device_list);
static DEFINE_MUTEX(device_list_lock);

static struct class *gt2440_nrf2401_class = NULL;

static const struct file_operations gt2440_nrf2401_fops = {
	.owner =	THIS_MODULE,
	.llseek 		= no_llseek,
	.unlocked_ioctl = gt2440_nrf2401_ioctl,
	.compat_ioctl    = gt2440_nrf2401_ioctl,
	.open 		= gt2440_nrf2401_open,
	.release 	=	 gt2440_nrf2401_release,
};



/***** write and read reg ****/
static int gt2440_nrf2401_write_reg (struct gt2440_nrf2401_info *info,
								unsigned char reg, unsigned char value)
{
	int ret;
	unsigned char tx_buf[4]={0};
	unsigned char rx_buf[4]={0};
	tx_buf[0] = reg ;
	tx_buf[1] = value;
	//ret = spi_write_then_read(info->spi_dev, tx_buf, 2, rx_buf, 1);
	ret = spi_write(info->spi_dev, tx_buf, 2);
	if (ret)
		dprintk("failed to write reg: "
			"addr=0x%02x, status=0x%02x, value=0x%02x, ret = %d\n", 
			reg, rx_buf[0], tx_buf[1],ret);
	return ret;
}
static int gt2440_nrf2401_read_reg (struct gt2440_nrf2401_info *info,
								unsigned char reg,unsigned char *value)
{
	unsigned char tx_buf[4];
	unsigned char rx_buf[4]={0xff};
	int ret;
	tx_buf[0] = reg;
	//tx_buf[1] = reg;
	ret = spi_write_then_read(info->spi_dev, tx_buf, 1, rx_buf, 2);
	if (ret)
		dprintk("failed to read reg: "
			"addr=0x%02x, status=0x%02x, value=0x%02x, ret = %d\n", 
			reg, rx_buf[0], rx_buf[1],ret);
	else
		*value = rx_buf[1];
	return ret;
}
static int gt2440_nrf2401_read_status(struct gt2440_nrf2401_info *info,
								unsigned char reg,unsigned char *value)
{
	unsigned char tx_buf[4];
	unsigned char rx_buf[4];
	int ret;
	tx_buf[0] = reg ;
	ret = spi_write_then_read(info->spi_dev, tx_buf, 1, rx_buf, 2);
	if (ret)
		dprintk("failed to read status: "
			"addr=0x%02x, status=0x%02x, ret = %d\n", 
			reg, rx_buf[0],ret);
	else
		*value = rx_buf[0];
	return ret;
}
static int gt2440_nrf2401_write_buf(struct gt2440_nrf2401_info *info,
								unsigned char reg, unsigned char *buf, 
								unsigned char len)
{
	int ret;
	unsigned char tx_buf[NRF2401_PIPE_LEN+ 4];
	unsigned char rx_buf[4];
	tx_buf[0] = reg ;
	memcpy(&tx_buf[1], buf, len);
	//ret = spi_write_then_read(info->spi_dev, tx_buf, len + 1, rx_buf, 1);
	ret = spi_write(info->spi_dev, tx_buf, len+1);
	if (ret)
		dprintk("failed to write buf: "
			"addr=0x%02x, status=0x%02x, value=0x%02x, ret = %d\n", 
			reg, rx_buf[0], *buf,ret);
	return ret;
} 
static int gt2440_nrf2401_read_buf(struct gt2440_nrf2401_info *info,
								unsigned char reg, unsigned char *buf, 
								unsigned char len)
{
	int i = 0;
	int ret = 0;
	for(i = 0; i < len; i++, buf++){
		ret = gt2440_nrf2401_read_reg(info, reg, buf);
	}
	return ret;
} 
/*
static int gt2440_nrf2401_read_buf(struct gt2440_nrf2401_info *info,
								unsigned char reg, unsigned char *buf, 
								unsigned char len)
{
	u8 tx_buf[INFO_BUFFER_SIZE + 1] = {0};
	u8 rx_buf[INFO_BUFFER_SIZE + 1] = {0};
	int ret;
	tx_buf[0] = reg ;
	ret = spi_write_then_read(info->spi_dev, tx_buf, 1, rx_buf, len + 1);
	if (ret)
		dprintk("failed to read buf: "
			"addr=0x%02x, status=0x%02x,value=0x%02x, ret = %d\n", 
			reg, rx_buf[0], rx_buf[1], ret);
	memcpy(buf, &rx_buf[1], len);
	return ret;
} 
*/

static int gt2440_nrf2401_set_tx_addr(struct gt2440_nrf2401_info *info)
{	dprintk("gt2440_nrf2401_set_tx_addr()\n");
	int ret;
	(info->pdata->clear_cepin)(info);	 
	ret = gt2440_nrf2401_write_buf(info, WRITE_REG1 | RX_ADDR_P0, 
						info->tx_addr, NRF2401_ADDR_LEN); 
	ret = gt2440_nrf2401_write_buf(info, WRITE_REG1 | TX_ADDR, 
						info->tx_addr, NRF2401_ADDR_LEN); 
	(info->pdata->set_cepin)(info);
	return ret;
}
static int gt2440_nrf2401_set_rx_addr(struct gt2440_nrf2401_info *info)
{	dprintk("gt2440_nrf2401_set_rx_addr()\n");
	int ret;
	(info->pdata->clear_cepin)(info);	 
	ret = gt2440_nrf2401_write_buf(info, 
						WRITE_REG1 | RX_ADDR_P0 + info->rx_addr_num, 
						info->rx_addr[info->rx_addr_num], 
						NRF2401_ADDR_LEN); 
	(info->pdata->set_cepin)(info);
	return ret;
}
static int gt2440_nrf2401_send_buf(struct gt2440_nrf2401_info *info)
{	dprintk("gt2440_nrf2401_send_buf()\n");
	int i = 0;
	int ret = 0;
	(info->pdata->clear_cepin)(info);		 
	gt2440_nrf2401_write_reg(info, WRITE_REG1 | STATUS,0xff);
	gt2440_nrf2401_write_reg(info, WRITE_REG1 | 0xe1,0);
	gt2440_nrf2401_write_reg(info, WRITE_REG1 | 0xe2,0);
	gt2440_nrf2401_write_reg(info, WRITE_REG1 |  CONFIG, 0x0e);				
	msleep(10); 

  	ret = gt2440_nrf2401_write_buf(info, WR_TX_PLOAD, 
						info->xfer->txrx_buf, NRF2401_PIPE_LEN);  
	(info->pdata->set_cepin)(info);
	info->tx_error = ret;
	if(ret == 0)
		wait_for_completion(&info->tx_done);
	
	return info->tx_error;
}

static int gt2440_nrf2401_recv_buf(struct gt2440_nrf2401_info *info)
{	dprintk("gt2440_nrf2401_recv_buf()\n");
	int i = 0;
	int ret = 0;
	(info->pdata->clear_cepin)(info);		 
	gt2440_nrf2401_write_reg(info, WRITE_REG1 | STATUS,0xff);
	gt2440_nrf2401_write_reg(info, WRITE_REG1 | 0xe1,0);
	gt2440_nrf2401_write_reg(info, WRITE_REG1 | 0xe2,0);
	gt2440_nrf2401_write_reg(info, WRITE_REG1 | CONFIG, 0x0f); 					
	msleep(10); 
	(info->pdata->set_cepin)(info);		

	mod_timer(&info->timer,
		jiffies + msecs_to_jiffies(10000));
	wait_for_completion(&info->rx_done);
	return info->rx_error;
}

static int gt2440_nrf2401_init_chip(struct gt2440_nrf2401_info *info)
{
	int ret = 0;
	unsigned char value=0xff;
	(info->pdata->clear_cepin)(info);		
			 
	gt2440_nrf2401_write_reg(info, WRITE_REG1 | EN_AA, 
						info->pdata->en_aa); 
	msleep(10);
	dprintk("write en aa reg: addr=0x%02x, value=0x%02x\n", 
			EN_AA, info->pdata->en_aa); 
	gt2440_nrf2401_read_reg(info,READ_REG1 | EN_AA, &value);
	dprintk("read en aa reg: addr=0x%02x, value=0x%02x\n", 
			EN_AA, value);
			
			
  	gt2440_nrf2401_write_reg(info, WRITE_REG1 | EN_RXADDR, 
						info->pdata->en_rxaddr); 
	gt2440_nrf2401_write_reg(info, WRITE_REG1 | RF_CH, 
						info->pdata->rf_ch); 
	gt2440_nrf2401_write_reg(info, WRITE_REG1 | SETUP_AW, 
						info->pdata->setup_aw); 
	gt2440_nrf2401_write_reg(info, WRITE_REG1 | SETUP_RETR, 
						info->pdata->setup_retr); 
	gt2440_nrf2401_write_reg(info, WRITE_REG1 | RF_CH, 
						info->pdata->rf_ch); 
	gt2440_nrf2401_write_reg(info, WRITE_REG1 | RF_SETUP, 
						info->pdata->rf_setup); 
	gt2440_nrf2401_write_reg(info, WRITE_REG1 | RX_PW_P0, 
						info->pdata->rx_pw_p0); 
	gt2440_nrf2401_write_reg(info, WRITE_REG1 | RX_PW_P1, 
						info->pdata->rx_pw_p1); 
	gt2440_nrf2401_write_reg(info, WRITE_REG1 | RX_PW_P2, 
						info->pdata->rx_pw_p2); 
	gt2440_nrf2401_write_reg(info, WRITE_REG1 | RX_PW_P3, 
						info->pdata->rx_pw_p3); 
	gt2440_nrf2401_write_reg(info, WRITE_REG1 | RX_PW_P4, 
						info->pdata->rx_pw_p4); 
	gt2440_nrf2401_write_reg(info, WRITE_REG1 | RX_PW_P5, 
						info->pdata->rx_pw_p5); 
  	gt2440_nrf2401_write_reg(info, WRITE_REG1 | CONFIG, 0x0f); 
  	
  	dprintk("write config reg: addr=0x%02x, value=0x%02x\n", 
			CONFIG, 0x0f); 
	gt2440_nrf2401_read_reg(info,READ_REG1 | CONFIG, &value);
	dprintk("read config reg: addr=0x%02x, value=0x%02x\n", 
			CONFIG, value);
	(info->pdata->set_cepin)(info);	
	

	return ret;
}
static int gt2440_nrf2401_deinit_chip(struct gt2440_nrf2401_info *info)
{
	int ret;
	(info->pdata->clear_cepin)(info);	
	gt2440_nrf2401_write_reg(info, WRITE_REG1 | CONFIG, 0x78); 
	(info->pdata->set_cepin)(info);	
	return ret;
}

static int gt2440_nrf2401_init_op(struct gt2440_nrf2401_info *info)
{	dprintk("gt2440_nrf2401_init_op()\n");
	int ret;
	ret = request_irq(info->irq, gt2440_nrf2401_irq, 
		info->irq_flags, info->spi_dev->modalias, info);
	if(ret < 0){
		dev_err(info->dev,"failed to request irq: %d, error=%d", 
			info->irq, ret);
		ret = -EBUSY;
		return ret;
	}
	
	gt2440_nrf2401_init_chip(info);

	return ret;
}

static int gt2440_nrf2401_deinit_op(struct gt2440_nrf2401_info *info)
{	dprintk("gt2440_nrf2401_deinit_op()\n");
	int ret;
	free_irq(info->irq, info);
	gt2440_nrf2401_deinit_chip(info);
	return ret;
}



/***** file ops function *****/
static int gt2440_nrf2401_pass_op(struct gt2440_nrf2401_info *info, 
								struct nrf2401_ioc_transfer *xfer)
{	dprintk("gt2440_nrf2401_pass_op()\n");
	int	ret = 0;
	switch(xfer->ioc_type){
	case NRF2401_IOC_NONE_0:
		break;
	case NRF2401_IOC_SET_CHIP:
		info->pdata->en_aa = xfer->txrx_buf[0];
		info->pdata->en_rxaddr = xfer->txrx_buf[1];
		info->pdata->setup_aw = xfer->txrx_buf[2];
		info->pdata->setup_retr = xfer->txrx_buf[3];
		info->pdata->rf_ch = xfer->txrx_buf[4];
		info->pdata->rf_setup = xfer->txrx_buf[5];
		
		info->pdata->rx_pw_p0 = xfer->txrx_buf[6];
		info->pdata->rx_pw_p1 = xfer->txrx_buf[7];
		info->pdata->rx_pw_p2 = xfer->txrx_buf[8];
		info->pdata->rx_pw_p3 = xfer->txrx_buf[9];
		info->pdata->rx_pw_p4 = xfer->txrx_buf[10];
		info->pdata->rx_pw_p5 = xfer->txrx_buf[11];
		gt2440_nrf2401_init_chip( info);
		break;
	case NRF2401_IOC_GET_CHIP:
		xfer->txrx_buf[0] = info->pdata->en_aa;
		xfer->txrx_buf[1] = info->pdata->en_rxaddr;
		xfer->txrx_buf[2] = info->pdata->setup_aw;
		xfer->txrx_buf[3] = info->pdata->setup_retr;
		xfer->txrx_buf[4] = info->pdata->rf_ch;
		xfer->txrx_buf[5] = info->pdata->rf_setup;
		
		xfer->txrx_buf[6] = info->pdata->rx_pw_p0;
		xfer->txrx_buf[7] = info->pdata->rx_pw_p1;
		xfer->txrx_buf[8] = info->pdata->rx_pw_p2;
		xfer->txrx_buf[9] = info->pdata->rx_pw_p3;
		xfer->txrx_buf[10] = info->pdata->rx_pw_p4;
		xfer->txrx_buf[11] = info->pdata->rx_pw_p5;		
		break;

	case NRF2401_IOC_READ_DATA:
		info->rx_addr_num = xfer->rx_addr_num;
		ret = memcmp(info->rx_addr[info->rx_addr_num], xfer->addr_buf, NRF2401_ADDR_LEN);
		if(ret){
			memcpy(info->rx_addr[xfer->rx_addr_num], 
				xfer->addr_buf, NRF2401_ADDR_LEN);
			ret = gt2440_nrf2401_set_rx_addr(info);	
		}else{

		}
		ret = gt2440_nrf2401_recv_buf(info);
		if(ret){
			dev_err(info->dev, "failed to recv buf\n");
		}
		break;
		
	case NRF2401_IOC_WRITE_DATA:
		ret = memcmp(info->tx_addr, xfer->addr_buf, NRF2401_ADDR_LEN);
		if(ret){
			memcpy(info->tx_addr, 
				xfer->addr_buf, NRF2401_ADDR_LEN);
			gt2440_nrf2401_set_tx_addr(info);
			//gt2440_nrf2401_set_rx_addr0(info);
		}else{

		}
		ret = gt2440_nrf2401_send_buf(info);
		if(ret){
			dev_err(info->dev, "failed to send buf\n");
		}
		//gt2440_nrf2401_reset_rx_addr0(info);
		break;
		
	default:
		break;

	}
	return ret;
}

static long gt2440_nrf2401_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{	dprintk("gt2440_nrf2401_ioctl()\n");
	struct gt2440_nrf2401_info *info;
	struct spi_device	*spi_dev;
	struct nrf2401_ioc_transfer	*xfer;
	unsigned		n_transfer;
	u32	tmp = 0, offset = 0, len = 0;
	int	err = 0, ret = 0;
	
	if (_IOC_TYPE(cmd) != SPI_IOC_MAGIC){
		dprintk("failed to get good magic code: \n", _IOC_TYPE(cmd));
		return -ENOTTY;
	}
	if (_IOC_DIR(cmd) & _IOC_READ)
		err = !access_ok(VERIFY_WRITE,
				(void __user *)arg, _IOC_SIZE(cmd));
	if (err == 0 && _IOC_DIR(cmd) & _IOC_WRITE)
		err = !access_ok(VERIFY_READ,
				(void __user *)arg, _IOC_SIZE(cmd));
	if (err){
		dprintk("failed to get read or write addr permission: \n", err);
		return -EFAULT;
	}
	info = filp->private_data;
	spin_lock_irq(&info->spi_lock);
	spi_dev = spi_dev_get(info->spi_dev);
	spin_unlock_irq(&info->spi_lock);
	if (spi_dev == NULL){
		dprintk("failed to get alive spi device : \n");
		return -ESHUTDOWN;
	}
	mutex_lock(&info->buf_lock);
	switch (cmd) {
	default:
		if (_IOC_NR(cmd) != _IOC_NR(SPI_IOC_MESSAGE(0))
				|| _IOC_DIR(cmd) != _IOC_WRITE) {
			dprintk("failed to get used massage : \n");
			ret = -ENOTTY;
			break;
		}
		tmp = _IOC_SIZE(cmd);
		if ((tmp % sizeof(struct nrf2401_ioc_transfer)) != 0) {
			dprintk("failed to get aligned massage : \n");
			ret = -EINVAL;
			break;
		}
		n_transfer = tmp / sizeof(struct nrf2401_ioc_transfer);
		if (n_transfer == 0 || n_transfer > 1){
			dprintk("failed to support more massage : \n");
			ret = -EINVAL;
			break;
		}
		xfer = kmalloc(tmp, GFP_KERNEL);
		if (!xfer) {
			dprintk("failed to allocate struct nrf2401_ioc_transfer{}: \n");
			ret = -ENOMEM;
			break;
		}
		if (__copy_from_user(xfer, (void __user *)arg, tmp)) {
			dprintk("failed to copy k space from u space: \n");
			kfree(xfer);
			ret = -EFAULT;
			break;
		}
		info->xfer = xfer;
		ret = gt2440_nrf2401_pass_op(info, xfer);
		if(ret){
			//dprintk("failed to pass operation\n");
			ret = -EFAULT;
		}else{
			switch(xfer->ioc_type){
			case NRF2401_IOC_GET_CHIP:
			case NRF2401_IOC_READ_DATA:

				len = NRF2401_PIPE_LEN;
				offset = (tmp - len);	
				if(__copy_to_user((u8 __user *)(arg)+offset, 
					((u8 *)xfer) + offset, 
					len )){
					dprintk("failed to copy k space to u space: \n");
					ret = -EFAULT;
				}
				break;
			default :
				break;	
			}
			;;;
		}
		kfree(xfer);
		info->xfer = NULL;
		break;

	/***** spi inferface mode set *****/
	case SPI_IOC_RD_MODE:
		ret = __put_user(spi_dev->mode & SPI_MODE_MASK,(__u8 __user *)arg);
		break;
	case SPI_IOC_RD_LSB_FIRST:
		ret = __put_user((spi_dev->mode & SPI_LSB_FIRST) ?  1 : 0,(__u8 __user *)arg);
		break;
	case SPI_IOC_RD_BITS_PER_WORD:
		ret = __put_user(spi_dev->bits_per_word, (__u8 __user *)arg);
		break;
	case SPI_IOC_RD_MAX_SPEED_HZ:
		ret = __put_user(spi_dev->max_speed_hz, (__u32 __user *)arg);
		break;
	case SPI_IOC_WR_MODE:
		ret = __get_user(tmp, (u8 __user *)arg);
		if (ret == 0) {
			u8	save = spi_dev->mode;
			if (tmp & ~SPI_MODE_MASK) {
				ret = -EINVAL;
				break;
			}
			tmp |= spi_dev->mode & ~SPI_MODE_MASK;
			spi_dev->mode = (u8)tmp;
			ret = spi_setup(spi_dev);
			if (ret < 0) 
				spi_dev->mode = save;
			else 
				dev_dbg(&spi_dev->dev, "spi mode %02x\n", tmp);
		}
		break;
	case SPI_IOC_WR_LSB_FIRST:
		ret = __get_user(tmp, (__u8 __user *)arg);
		if (ret == 0) {
			u8	save = spi_dev->mode;
			if (tmp)
				spi_dev->mode |= SPI_LSB_FIRST;
			else 
				spi_dev->mode &= ~SPI_LSB_FIRST;
			ret = spi_setup(spi_dev);
			if (ret < 0) 
				spi_dev->mode = save;
			else 
				dev_dbg(&spi_dev->dev, "%csb first\n",tmp ? 'l' : 'm');
		}
		break;
	case SPI_IOC_WR_BITS_PER_WORD:
		ret = __get_user(tmp, (__u8 __user *)arg);
		if (ret == 0) {
			u8	save = spi_dev->bits_per_word;
			spi_dev->bits_per_word = tmp;
			ret = spi_setup(spi_dev);
			if (ret < 0) 
				spi_dev->bits_per_word = save;
			else 
				dev_dbg(&spi_dev->dev, "%d bits per word\n", tmp);
		}
		break;
	case SPI_IOC_WR_MAX_SPEED_HZ:
		ret = __get_user(tmp, (__u32 __user *)arg);
		if (ret == 0) {
			u32	save = spi_dev->max_speed_hz;
			spi_dev->max_speed_hz = tmp;
			ret = spi_setup(spi_dev);
			if (ret < 0) 
				spi_dev->max_speed_hz = save;
			else 
				dev_dbg(&spi_dev->dev, "%d Hz (max)\n", tmp);
		}
		break;
	}
	mutex_unlock(&info->buf_lock);
	spi_dev_put(spi_dev);
	return ret;
}

static int gt2440_nrf2401_open(struct inode *inode, struct file *filp)
{	dprintk("gt2440_nrf2401_open()\n");
	struct gt2440_nrf2401_info *info;
	int ret = -ENXIO;
	mutex_lock(&device_list_lock);
	list_for_each_entry(info, &device_list, device_entry) {
		if (info->devt == inode->i_rdev) {
			ret = 0;
			break;
		}
	}
	if (ret == 0) {
		if(info->users == 0){	
			//if(ret = gt2440_nrf2401_init_op(info)){
			//	dev_err(&info->spi_dev->dev, "failed to init nrf2401\n");
			//}
		}
		info->users++;
		filp->private_data = info;
		nonseekable_open(inode, filp);
	} else 
		pr_debug("nrf2401: nothing for minor %d\n", iminor(inode));
	mutex_unlock(&device_list_lock);

	return ret;
}
static int gt2440_nrf2401_release(struct inode *inode, struct file *filp)
{	dprintk("gt2440_nrf2401_release()\n");
	struct gt2440_nrf2401_info *info;
	int ret = 0;
	mutex_lock(&device_list_lock);
	info = filp->private_data;
	filp->private_data = NULL;
	info->users--;
	if (!info->users) {
			//if(ret = gt2440_nrf2401_deinit_op(info)){
			//	dev_err(&info->spi_dev->dev, "failed to deinit nrf2401\n");
			//}
		int dofree;
		spin_lock_irq(&info->spi_lock);
		dofree = (info->spi_dev == NULL);
		spin_unlock_irq(&info->spi_lock);
		if (dofree) kfree(info);
	}
	mutex_unlock(&device_list_lock);
	return ret ;
}



/***** interrupt function ****/
static void gt2440_nrf2401_irq_work(struct work_struct *work)
{	dprintk("gt2440_nrf2401_irq_work()\n");
	struct gt2440_nrf2401_info *info =
		container_of(work, struct gt2440_nrf2401_info, irq_work);
	unsigned	char status;
	int i=0;

	gt2440_nrf2401_read_status(info, READ_REG1 |STATUS, &status);	
	dev_info(info->dev,"read status reg: 0x%02x,0x%02x \n", STATUS, status);
	
	if(status & 0x40){	/***** rx new pipe data *****/
		
	 	gt2440_nrf2401_read_buf(info, READ_REG1 |RD_RX_PLOAD,
			info->xfer->txrx_buf, NRF2401_PIPE_LEN);
		if((status&0x0e)<=0x0a){						   
		  	info->rx_addr_num = (status&0x0e) >> 1;
		}else 
			info->rx_addr_num = 0;
			
		dprintk("read  FIFO data: pipe num=%d", info->rx_addr_num );
		for(i = 0; i<NRF2401_PIPE_LEN; i++){
			if(i%4 == 0) dprintk("\n");
			dprintk("0x%02x  ",info->xfer->txrx_buf[i]);
		}
		dprintk("\nread FIFO data: end\n");
		
		info->rx_error = 0;
		complete(&info->rx_done);
	
	}else if((status &0x20)>0){		/***** rx ack , tx ok *****/
		info->tx_error = 0;
		complete(&info->tx_done);
		gt2440_nrf2401_write_reg(info, 0xe1,0);	
		
	}else if((status &0x10)>0){/***** retransmit count overflow error *****/	
		info->tx_error = 1;
		complete(&info->tx_done);
		gt2440_nrf2401_write_reg(info, 0xe1,0);	
		
	}
	gt2440_nrf2401_write_reg(info, WRITE_REG1 | STATUS, status);

	return ;
}


static irqreturn_t gt2440_nrf2401_irq(int irq, void *dev_id)
{	dprintk("gt2440_nrf2401_irq()\n");
	struct gt2440_nrf2401_info *info = dev_id;
	/***** critical ops: do not anything directly, 
	****** because the spi_sync() will go to sleep .
	*****/
	schedule_work(&info->irq_work);

	return IRQ_HANDLED;
}

static void gt2440_nrf2401_timer(unsigned long data)
{
	struct gt2440_nrf2401_info *info = (struct gt2440_nrf2401_info *)data;

	//complete(&info->tx_done);
	complete(&info->rx_done);
}



#define GT2440_NRF2401_SEND


/***** probe and remove function ****/
#ifdef GT2440_NRF2401_TEST
void gt2440_nrf2401_test_chip(struct gt2440_nrf2401_info *info)
{	
	/* only for test mode, normal mode will remove follow code  */
	gt2440_nrf2401_init_op(info);
	int i = 0;
	int loops = 0;
	int ret = 0;
#ifdef GT2440_NRF2401_SEND
	struct nrf2401_ioc_transfer xfer={
		.ioc_type = NRF2401_IOC_WRITE_DATA,
	};
	for(i = 0; i<NRF2401_ADDR_LEN; i++){
		xfer.addr_buf[i] = (u8)0x01;
	}

	for(i = 0; i<NRF2401_PIPE_LEN; i++){
		xfer.txrx_buf[i] = (u8)0x24;
	}
	info->xfer = &xfer;
	
	loops = 1;
	while(loops--){
		ret = gt2440_nrf2401_pass_op(info, &xfer);
		if(ret ){
			dev_err(info->dev, "failed to send data\n");
		}else{
			dev_info(info->dev, 
				"good to send data on addr: 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x\n", 
					xfer.addr_buf[0], xfer.addr_buf[1],
					xfer.addr_buf[2], xfer.addr_buf[3],
					xfer.addr_buf[4]);
			
			for(i = 0; i< NRF2401_PIPE_LEN; i++){
				if(i%4 == 0) 
					dprintk("\n");
				dprintk("0x%02x	",xfer.txrx_buf[i] );
			}
			dprintk("\n");
		}
		msleep(1000);
	}
	
#else
	struct nrf2401_ioc_transfer xfer={
		.ioc_type = NRF2401_IOC_READ_DATA,
		.rx_addr_num = 1,
	};

	for(i = 0; i<NRF2401_ADDR_LEN; i++){
		xfer.addr_buf[i] = (u8)0x01;
	}

	for(i = 0; i<NRF2401_PIPE_LEN; i++){
		xfer.txrx_buf[i] = (u8)0x00;
	}
	info->xfer = &xfer;
	
	loops = 1;
	while(loops--){
		ret = gt2440_nrf2401_pass_op(info, &xfer);
		if(ret ){
			dev_err(info->dev, "failed to recv data\n");
		}else{
			dev_info(info->dev, 
				"good to recv data on addr: 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x\n", 
					xfer.addr_buf[0], xfer.addr_buf[1],
					xfer.addr_buf[2], xfer.addr_buf[3],
					xfer.addr_buf[4]);
			
			for(i = 0; i< NRF2401_PIPE_LEN; i++){
				if(i%4 == 0) 
					dprintk("\n");
				dprintk("0x%02x	",xfer.txrx_buf[i] );
			}
			dprintk("\n");
		}
		msleep(1000);
	}

#endif
	
}
#else
void gt2440_nrf2401_test_chip(struct gt2440_nrf2401_info *info){}
#endif
static int gt2440_nrf2401_probe(struct spi_device *spi_dev)
{	dprintk("gt2440_nrf2401_probe(id=%d.%d)\n", spi_dev->master->bus_num, spi_dev->chip_select);
	struct gt2440_nrf2401_info *info;
	struct gt2440_nrf2401_platdata *pdata;
	unsigned long minor;
	int ret;
	pdata = spi_dev->dev.platform_data;
	if (pdata == NULL) {
		dev_err(&spi_dev->dev,"failed to get platform_data\n");
		return -EINVAL;
	}
	
	info = kzalloc(sizeof(struct gt2440_nrf2401_info), GFP_KERNEL);
	if (info == NULL) {
		dev_err(&spi_dev->dev,"failed to allocate struct gt2440_nrf2401_info{}\n");
		return -ENOMEM;
	}
	info->pdata = pdata;

	info->irq = spi_dev->irq;
	
	info->ce_pin = pdata->ce_pin;
	info->irq_pin = pdata->irq_pin;
	info->irq_flags = pdata->irq_flags;


	info->spi_dev = spi_dev;
	info->dev = &spi_dev->dev;

	memcpy(info->name, "gt2440_nrf2401", sizeof("gt2440_nrf2401"));
	
	INIT_LIST_HEAD(&info->device_entry);
	spin_lock_init(&info->spi_lock);
	mutex_init(&info->buf_lock);
	init_completion(&info->tx_done);
	init_completion(&info->rx_done);
	INIT_WORK(&info->irq_work, gt2440_nrf2401_irq_work);
	setup_timer(&info->timer, gt2440_nrf2401_timer, (unsigned long)info);
	spi_set_drvdata(spi_dev, info);
	
	mutex_lock(&device_list_lock);
	minor = find_first_zero_bit(minors, N_SPI_MINORS);
	if (minor < N_SPI_MINORS) {
		struct device *dev;
		info->devt = MKDEV(SPICHAR_MAJOR, minor);
		dev = device_create(gt2440_nrf2401_class, &spi_dev->dev, info->devt,
				    info, "nrf2401-%d.%d",
				    spi_dev->master->bus_num, spi_dev->chip_select);
		 if(IS_ERR(dev)){
			dev_dbg(&spi_dev->dev, "failed to create device \n");
			ret = IS_ERR(dev) ;
			goto exit_1;
		 }
	} else {
		dev_err(&spi_dev->dev, "failed to allocate minor number \n");
		ret = -ENODEV;
		goto exit_1;
	}
	set_bit(minor, minors);
	list_add(&info->device_entry, &device_list);
	mutex_unlock(&device_list_lock);
	

	gt2440_nrf2401_test_chip(info);
	
	return 0;
		
exit_1:
	kfree(info);
	spi_set_drvdata(spi_dev, NULL);
	return ret;
}

static int gt2440_nrf2401_remove(struct spi_device *spi_dev)
{	dprintk("gt2440_nrf2401_remove(id=%d.%d)\n", 
		spi_dev->master->bus_num, spi_dev->chip_select);
	struct gt2440_nrf2401_info *info = spi_get_drvdata(spi_dev);
	if(info == NULL) 
		return 0;
		
	gt2440_nrf2401_deinit_op(info);
	
	spin_lock_irq(&info->spi_lock);
	info->spi_dev = NULL;
	spi_set_drvdata(spi_dev, NULL);
	spin_unlock_irq(&info->spi_lock);
	
	mutex_lock(&device_list_lock);
	list_del(&info->device_entry);
	device_destroy(gt2440_nrf2401_class, info->devt);
	clear_bit(MINOR(info->devt), minors);
	
	if (info->users == 0) 
		kfree(info);
	mutex_unlock(&device_list_lock);

	
	return 0;
}


static struct spi_driver gt2440_nrf2401_spi_driver = {
	.driver = {
		.name =	SPI_DEVICE_NAME,	/* nrf2401 != spidev*/
		.owner =	THIS_MODULE,
	},
	.probe 	= gt2440_nrf2401_probe,
	.remove = gt2440_nrf2401_remove,
};



/***** init and exit ****/
static int __init gt2440_nrf2401_init(void)
{	dprintk("gt2440_nrf2401_init()\n");
	int ret;

	BUILD_BUG_ON(N_SPI_MINORS > 256);
	ret = register_chrdev(SPICHAR_MAJOR, SPI_DEVICE_NAME, &gt2440_nrf2401_fops);
	if (ret < 0){
		printk(KERN_ERR"failed to register char device\n");
		ret = -EINVAL;
		return ret;
	}
	gt2440_nrf2401_class = class_create(THIS_MODULE, SPI_DEVICE_NAME);
	if (IS_ERR(gt2440_nrf2401_class)) {
		printk(KERN_ERR"failed to create class\n");
		ret = PTR_ERR(gt2440_nrf2401_class);
		goto exit_1;
	}
	ret = spi_register_driver(&gt2440_nrf2401_spi_driver);
	if (ret < 0) {
		printk(KERN_ERR"failed to register spi driver\n");
		goto exit_2;
	}
	return 0;

exit_2:
	class_destroy(gt2440_nrf2401_class);
	gt2440_nrf2401_class = NULL;
exit_1:
	unregister_chrdev(SPICHAR_MAJOR, 
		gt2440_nrf2401_spi_driver.driver.name);
	return ret;
}
static void __exit gt2440_nrf2401_exit(void)
{	dprintk("gt2440_nrf2401_exit()\n");
	spi_unregister_driver(&gt2440_nrf2401_spi_driver);
	class_destroy(gt2440_nrf2401_class);
	unregister_chrdev(SPICHAR_MAJOR, 
		gt2440_nrf2401_spi_driver.driver.name);
}
module_init(gt2440_nrf2401_init);
module_exit(gt2440_nrf2401_exit);
MODULE_DESCRIPTION("GT2440 NRF2401 SPI Network Device Driver");
MODULE_AUTHOR("Liguang13579<1659890447@qq.com>");
MODULE_LICENSE("GPL v2");


